Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

re-add shadow DOM styles when reparented #2252

Merged
merged 9 commits into from
Sep 20, 2024
Merged

Conversation

mayank99
Copy link
Contributor

@mayank99 mayank99 commented Sep 18, 2024

Changes

This PR fixes #2230 by re-creating the CSSStyleSheet inside ShadowRoot whenever the appui:reparent event is emitted. This event was added in iTwin/appui#946 specifically to be consumed by our ShadowRoot component, in order to support the "reparent widget" feature (there is more info in iTwin/appui#893 if you're curious).

It's not perfect and there is room for improvement, but it fixes the bug. The main issue right now is that we are unable to properly narrow down the reparented target, which means we are calling createStyleSheet every time appui:reparent is dispatched anywhere in the window. We do have additional checks for stylesheet, so we're not unnecessarily recreating lots of stylesheets. Just something to be aware of and improve in the future.

  • After-PR TODO: Optimize the above situation.

Testing

Since this is AppUI-specific functionality, it is hard for us to test directly. But it was confirmed to work in AppUI's own test app (see thread below).

I did add a small e2e test to ensure we are not regressing on the most basic use of popout.

Docs

Added changeset.

@mayank99 mayank99 self-assigned this Sep 18, 2024
Comment on lines 138 to 144
// Re-create stylesheet if the element is moved to a different window (by AppUI)
React.useEffect(() => {
window.addEventListener('appui:reparent', createStyleSheet);
return () => {
window.removeEventListener('appui:reparent', createStyleSheet);
};
}, [createStyleSheet, latestShadowRoot]);
Copy link
Contributor Author

@mayank99 mayank99 Sep 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@GerardasB What do you think would be the best way to test this? It would be difficult to add a proper test for this in iTwinUI without manually recreating the custom event / reparenting logic.

I'm thinking we first manually verify that it works within the AppUI repo (by editing @itwin/itwinui-react in node_modules) and then after this is released, we can update the existing AppUI test scenario to ensure the styles look fine without any special handling on top of ProgressRadial.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, I'll verify if this change works and let you know.

Copy link

@GerardasB GerardasB Sep 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can confirm, this works correctly in the reparenting use-case (I made sure to remove the custom useEffect workaround https://github.com/iTwin/appui/blob/b1c1d0c95a58ebbf2985bb2e61ad01d639e7f795/apps/test-app/src/frontend/appui/frontstages/TestPopoutFrontstage.tsx#L90)

However, this change breaks the regular use-case, where no reparenting is done and the component is simply mounted in a new window. (reparentPopoutWidgets=0 to configure in AppUI test-app: https://github.com/iTwin/appui/blob/b1c1d0c95a58ebbf2985bb2e61ad01d639e7f795/e2e-tests/tests/popout-widget.test.ts#L210)

This happens because useEffect that is scheduled in useLatestRef(shadowRoot) runs after the createStyleSheet called after ReactDOM4.flushSync(), which results in createStyleSheet returning early due to null latestShadowRoot.current.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for testing it. I believe I've fixed the regular popout case in my latest changes. I'm passing the already existing shadow into createStyleSheet (rather than relying on useLatestRef).

I also added a basic test for it, since this test does not require us to reimplement any reparenting logic.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good now!

@mayank99 mayank99 marked this pull request as ready for review September 19, 2024 16:54
@mayank99 mayank99 requested a review from a team as a code owner September 19, 2024 16:54
@mayank99 mayank99 requested review from r100-stack and smmr-dn and removed request for a team September 19, 2024 16:54
@mayank99 mayank99 merged commit 3df74c0 into main Sep 20, 2024
17 of 18 checks passed
@mayank99 mayank99 deleted the mayank/fix-reparent-styles branch September 20, 2024 14:32
@imodeljs-admin imodeljs-admin mentioned this pull request Sep 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Preview popout reparent: iTwinUI ProgressRadial shows "Loading" text when popped out
3 participants